﻿using System.Transactions;
using CNav.Business;
using CNav.Business.Validation;
using CNav.Common;
using CNav.DataEntity;
using CNav.Domain;
using System;
using System.Collections.Generic;
using System.Linq;
using FluentValidation.Results;

namespace CNav.Business.Services
{
    public interface IConsumerService
    {
        ResponseData<bool> AddConsumer(Consumer consumer, Address address);
        ResponseData<Consumer> UpdateConsumer(Consumer consumer, Address address);
        ResponseData<bool> DeleteConsumer(int id);
        ResponseData<List<Consumer>> GetConsumers();
        ResponseData<Consumer> GetConsumer(int id);
    }

    public class ConsumerService : ServiceBase, IConsumerService
    {
        public ResponseData<bool> AddConsumer(Consumer consumer, Address address)
        {
            var response = new ResponseData<bool>();

            var consumerValidator = new ConsumerValidation();
            var consumerResult = consumerValidator.Validate(consumer);

            var addressValidator = new AddressValidation();
            ValidationResult addressResult = addressValidator.Validate(address);

            if (addressResult.IsValid && consumerResult.IsValid)
            {
                var tempConsumer = Context.Get<ConsumerDto>(c => c.FirstName == consumer.FirstName
                    && c.LastName == consumer.LastName && c.BirthDate== consumer.BirthDate
                    ).ToList().FirstOrDefault();

                if (tempConsumer != null)
                {
                    response.Error = new[] { "Consumer already registered." };
                    return response;
                }

                using (var scope = new TransactionScope())
                {
                    var consumerDto = new ConsumerDto();

                    consumerDto.Title = consumer.Title;
                    consumerDto.FirstName = consumer.FirstName;
                    consumerDto.MiddleName = consumer.MiddleName;
                    consumerDto.LastName = consumer.LastName;
                    consumerDto.BirthDate = consumer.BirthDate;
                    consumerDto.Email = consumer.Email.ToUpper();
                    consumerDto.PhoneNumber = consumer.PhoneNumber;
                    consumerDto.FaxNumber = consumer.FaxNumber;
                    consumerDto.AdminComment = consumer.AdminComment;
                    consumerDto.CreatedOnUtc = DateTime.UtcNow;
                    consumerDto.AddressID = consumer.AddressID;
                  
                    var addressDto = new AddressDto();
                    addressDto.Address1 = address.Address1;
                    addressDto.Address2 = address.Address2;
                    addressDto.City = address.City;
                    addressDto.CountryID = address.CountryID;
                    addressDto.PostalCode = address.PostalCode;
                    addressDto.State = address.State;

                    consumerDto.Address = addressDto;
                    Context.Repository<AddressDto>().Add(addressDto);
                    Context.Repository<ConsumerDto>().Add(consumerDto);

                    Context.Commit();
                    scope.Complete();

                    response.Data = true;
                    return response;
                }
            }
            response.Error = consumerResult.ErrorList().Union(addressResult.ErrorList());
            return response;
        }

        private bool ConsumerExist(int id)
        {
            var consumerDto = Context.Get<ConsumerDto>(c => c.ID == id).ToList()
                  .FirstOrDefault();

            return consumerDto != null;
        }

        public ResponseData<Consumer> UpdateConsumer(Consumer consumer, Address address)
        {
            var response = new ResponseData<Consumer>();

            var validator = new ConsumerValidation();
            var result = validator.Validate(consumer);
            if (result.IsValid)
            {
                if (ConsumerExist(consumer.ID))
                {
                    var consumerDto = Context.Get<ConsumerDto>(c => c.ID == consumer.ID).ToList().FirstOrDefault();

                    consumerDto.Title = consumer.Title;
                    consumerDto.FirstName = consumer.FirstName;
                    consumerDto.MiddleName = consumer.MiddleName;
                    consumerDto.LastName = consumer.LastName;
                    consumerDto.BirthDate = consumer.BirthDate;
                    consumerDto.Email = consumer.Email.ToUpper();
                    consumerDto.PhoneNumber = consumer.PhoneNumber;
                    consumerDto.FaxNumber = consumer.FaxNumber;
                    consumerDto.AdminComment = consumer.AdminComment;
                    consumerDto.LastActivityDateUtc = DateTime.UtcNow;
                    consumerDto.AddressID = consumer.AddressID;

                    var addressDto = Context.Get<AddressDto>(a => a.ID == consumer.AddressID).ToList().First();

                    addressDto.Address1 = address.Address1;
                    addressDto.Address2 = address.Address2;
                    addressDto.City = address.City;
                    addressDto.CountryID = address.CountryID;
                    addressDto.PostalCode = address.PostalCode;
                    addressDto.State = address.State;

                    Context.Repository<AddressDto>().Update(addressDto);
                    Context.Repository<ConsumerDto>().Update(consumerDto);
                    Context.Commit();
                    response = GetConsumer(consumer.ID);

                    return response;
                }
                response.Error = new[] { "Consumer does not exist." };
                return response;
            }
            response.Error = result.ErrorList();
            return response;
        }

        public ResponseData<bool> DeleteConsumer(int id)
        {
            var response = new ResponseData<bool>();

            var consumerDto = Context.Get<ConsumerDto>(c => c.ID == id).ToList().FirstOrDefault();
            if (consumerDto != null)
            {
                var addressDto = Context.Get<AddressDto>(a => a.ID == id).ToList().FirstOrDefault();

                Context.Repository<ConsumerDto>().Delete(consumerDto);
                Context.Repository<AddressDto>().Delete(addressDto);
                Context.Commit();

                response.Data = true;
                return response;
            }
            response.Error = new[] { "Consumer does not exist." };
            return response;
        }

        public ResponseData<List<Consumer>> GetConsumers()
        {
            var response = new ResponseData<List<Consumer>>();
            var consumerDtos = Context.Get<ConsumerDto>().ToList();

            response.Data = consumerDtos.Select(consumer => new Consumer
            {
                ID = consumer.ID,
                Title = consumer.Title,
                FirstName = consumer.FirstName,
                MiddleName = consumer.MiddleName,
                LastName = consumer.LastName,
                BirthDate = consumer.BirthDate,
                Email = consumer.Email,
                PhoneNumber = consumer.PhoneNumber,
                FaxNumber = consumer.FaxNumber,
                AdminComment = consumer.AdminComment,
                CreatedOnUtc = DateTime.UtcNow,
                AddressID = consumer.AddressID,
                LastActivityDateUtc = consumer.LastActivityDateUtc
            }).ToList();
            return response;
        }

        public ResponseData<Consumer> GetConsumer(int id)
        {
            var response = new ResponseData<Consumer>();
            var consumerDto = Context.Get<Consumer>(c => c.ID == id).ToList().FirstOrDefault();
            if (consumerDto != null)
            {
                var consumer = new Consumer
                {
                    ID = consumerDto.ID,
                    Title = consumerDto.Title,
                    FirstName = consumerDto.FirstName,
                    MiddleName = consumerDto.MiddleName,
                    LastName = consumerDto.LastName,
                    BirthDate = consumerDto.BirthDate,
                    Email = consumerDto.Email,
                    PhoneNumber = consumerDto.PhoneNumber,
                    FaxNumber = consumerDto.FaxNumber,
                    AdminComment = consumerDto.AdminComment,
                    CreatedOnUtc = DateTime.UtcNow,
                    AddressID = consumerDto.AddressID,
                    LastActivityDateUtc = consumerDto.LastActivityDateUtc
                };

                response.Data = consumer;
                return response;
            }
            response.Error = new[] { "Consumer id does not exist." };
            return response;
        }
    }
}